package com.xjh.serverinspect.inspect.service.impl;

import com.xjh.serverinspect.inspect.service.InspectService;
import com.xjh.serverinspect.security.PasswordUtils;
import com.xjh.serverinspect.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 *
 * </p>
 *
 * @author xujinghui
 * @since 2024-10-14
 */
@Service
@Slf4j
public class InspectServiceImpl implements InspectService {

    @Resource
    private CommandConf commandConf;

    /**
     * 系统检查
     *
     * @return List<Result>
     */
    @Override
    public List<Result> systemCheck() {
        ArrayList<Result> results = new ArrayList<>();
        List<CommandConf.Server> servers = commandConf.getServers();
        for (CommandConf.Server server : servers) {
            long st = System.currentTimeMillis();
            Result result = new Result();
            List<ResultItem> resultItems = new ArrayList<>();
            if (server.getShell() != null)
                resultItems.addAll(executeShell(server));
            if (server.getSql() != null)
                resultItems.addAll(executeSql(server));
            result.setTitle(server.getHost());
            result.setItems(resultItems);
            result.setTime(System.currentTimeMillis() - st);
            results.add(result);
        }

        return results;
    }

    /**
     * 执行shell命令
     *
     * @param server 服务器配置
     * @return
     */
    private List<ResultItem> executeShell(CommandConf.Server server) {
        List<ResultItem> resultItems = new ArrayList<>();
        SshdExecutor sshdExecutor = null;
        try {
            CommandConf.Shell shell = server.getShell();
            CommandConf.Shell sh = commandConf.getShell();
            Integer port = shell.getPort() != null ? shell.getPort() : sh.getPort();
            String username = StringUtils.hasText(shell.getUsername()) ? shell.getUsername() : sh.getUsername();
            String password = StringUtils.hasText(shell.getPassword()) ? shell.getPassword() : sh.getPassword();
            sshdExecutor = new SshdExecutor(server.getHost(), port, username, PasswordUtils.decrypt(password));

            List<CommandConf.Command> commands = shell.getCommands();
            if (sh.getCommands() != null) {
                commands.addAll(sh.getCommands());
            }
            for (CommandConf.Command command : commands) {
                String[] resultTuple = sshdExecutor.executeCommand(command.getScript());
                ResultItem resultItem = null;
                switch (command.getResultType()) {
                    case "table":
                        resultItem = ShellResultConvert.convert2table(resultTuple, command.getDescription());
                        break;
                    case "text":
                        resultItem = ShellResultConvert.convert2text(resultTuple, command.getDescription());
                        break;
                    case "file-list":
                        resultItem = ShellResultConvert.convert2fileList(resultTuple, command.getDescription());
                        break;
                    case "pid-list":
                        resultItem = ShellResultConvert.convert2pidList(resultTuple, command.getDescription());
                        break;
                    default:
                        break;
                }
                resultItems.add(resultItem);
            }
            return resultItems;
        } catch (Exception e) {
            log.error("shell execute error", e);
        } finally {
            if (sshdExecutor != null)
                sshdExecutor.close();
        }
        return null;
    }

    /**
     * 执行sql命令
     *
     * @param server 服务器配置
     * @return
     */
    private List<ResultItem> executeSql(CommandConf.Server server) {
        List<ResultItem> resultItems = new ArrayList<>();
        ConnectionWrapper conn = null;
        try {
            CommandConf.Sql sql = server.getSql();
            CommandConf.Sql sq = commandConf.getSql();
            String database = StringUtils.hasText(sql.getDatabase()) ? sql.getDatabase() : sq.getDatabase();
            Integer port = sql.getPort() != null ? sql.getPort() : sq.getPort();
            String username = StringUtils.hasText(sql.getUsername()) ? sql.getUsername() : sq.getUsername();
            String password = StringUtils.hasText(sql.getPassword()) ? sql.getPassword() : sq.getPassword();
            conn = DatabaseUtils.getConnection(database, server.getHost(), port, username, PasswordUtils.decrypt(password));
            List<CommandConf.Command> commands = sql.getCommands();
            if (sq.getCommands() != null) {
                commands.addAll(sq.getCommands());
            }
            for (CommandConf.Command command : commands) {
                ResultItem resultItem;
                ConnectionWrapper.ResultSetWrapper rs = conn.executeQuery(command.getScript());
                if (StringUtils.hasText(rs.getError())) {
                    resultItem = new ResultItem();
                    resultItem.setContentType("table");
                    resultItem.setMetaData(new String[]{"错误信息"});
                    resultItem.setRows(Collections.singletonList(new String[]{String.format("<font color='#F56C6C'>%s</font>", rs.getError())}));
                } else {
                    resultItem = DatabaseUtils.resultSet2ResultItem(rs.getResultSet());
                }
                resultItem.setTitle(command.getDescription());
                resultItems.add(resultItem);
            }
        } catch (SQLException e) {
            log.error("sql execute error", e);
        } finally {
            if (conn != null)
                conn.close();
        }
        return resultItems;
    }

}
